package bleudp

import (
	"context"
	"iot-ble-server/dgram"
	"iot-ble-server/global/globallogger"
	"iot-ble-server/global/globalsocket"
	"iot-ble-server/internal/config"
	"iot-ble-server/internal/packets"
)

// Start ble udp server
func Start(ctx context.Context) error {
	globallogger.Log.Errorln("Start ble udp server")
	globalsocket.ServiceSocket = dgram.CreateUDPSocket(config.C.General.BindPort)
	go func() {
		defer globalsocket.ServiceSocket.Close()
		data := make([]byte, 1024)
		for {
			select {
			case <-ctx.Done():
				return
			default:
				msg, rinfo, err := globalsocket.ServiceSocket.Receive(data)
				if err != nil {
					globallogger.Log.Errorln(err)
					return
				}
				go UDPMsgProc(ctx, msg, rinfo)
			}
		}
	}()
	return nil
}

func UDPMsgProc(ctx context.Context, msg []byte, rinfo dgram.RInfo) {
	// defer func() {
	// 	err := recover()
	// 	if err != nil {
	// 		globallogger.Log.Errorf("<UDPMsgProc> err :%v", err)
	// 	}
	// }()
	if checkMsgSafe(msg) {
		globallogger.Log.Debugln("<UDPMsgProc> start parsing UDP packets from: IP", rinfo.Address, "the port is:", rinfo.Port, "data is:", msg)
		procMessage(ctx, msg, rinfo)
	}
}

func procMessage(ctx context.Context, data []byte, rinfo dgram.RInfo) {
	jsonInfo, err := parseUdpMessage(data, rinfo)
	if err != nil {
		if jsonInfo.MessageAppHeader.Type != packets.BleBoardcast {
			globallogger.Log.Errorf("<procMessage> current msg type is [%v] TLVMsg is [%v] with %v", jsonInfo.MessageAppHeader.Type, jsonInfo.MessageAppBody.TLV.TLVMsgType, err)
		} else { //不合规的广播报文不显示打印
			globallogger.Log.Debugln("<procMessage> UDP packets from:", rinfo.Address, "with an error:", err)
		}
		return
	}
	if jsonInfo.MessageHeader.Version != packets.Version3 {
		globallogger.Log.Errorf("<procMessage> [GwDevEui: %s] UDP version is illegal", jsonInfo.MessageBody.GwMac)
		return
	}
	//暂行
	if len(jsonInfo.MessageAppBody.MultiTLV) > 0 && jsonInfo.MessageAppBody.MultiTLV[0].TLVPayload.DevMac != "" && jsonInfo.MessageAppBody.MultiTLV[0].TLVPayload.DevMac != "2022000636bf" {
		return
	}
	globallogger.Log.Errorf("<procMessage> [GwDevEui: %v] current proc LinkMsg is [%v], AppMsg is [%v], TLVType is [%v]",
		jsonInfo.MessageBody.GwMac, jsonInfo.MessageHeader.LinkMsgType, jsonInfo.MessageAppHeader.Type, jsonInfo.MessageAppBody.TLV.TLVMsgType)
	switch jsonInfo.MessageHeader.LinkMsgType[0:2] {
	case packets.ChannelControl:
		procChannelMsg(ctx, jsonInfo, jsonInfo.MessageBody.GwMac)
	case packets.GatewayManager:
		if CheckGatewayInfo(ctx, jsonInfo.MessageBody.GwMac) {
			procGatewayMsg(ctx, jsonInfo, jsonInfo.MessageBody.GwMac)
		}
	case packets.TerminalManager:
		if CheckGatewayInfo(ctx, jsonInfo.MessageBody.GwMac) {
			procTerminalMsg(ctx, jsonInfo, jsonInfo.MessageBody.GwMac+jsonInfo.MessageAppBody.TLV.TLVPayload.DevMac)
		}
	default:
		globallogger.Log.Errorf("procMessage: [DevEui: %s] received unrecognized link message type", jsonInfo.MessageBody.GwMac)
	}
}

//链路消息处理
func procChannelMsg(ctx context.Context, jsonInfo packets.JsonUdpInfo, devEui string) {
	switch jsonInfo.MessageHeader.LinkMsgType {
	case packets.Hello:
		procHelloAck(ctx, jsonInfo, devEui)
	case packets.GerenalResponse:
		globallogger.Log.Errorf("<procChannelMsg> [Gateway DevEui: %s] received exception message, which send type: %s", devEui, jsonInfo.MessageBody.WaitConfirmMsg)
	default:
		globallogger.Log.Errorf("<procChannelMsg> [Gateway DevEui: %s] received unrecognized link message type: %s", devEui, jsonInfo.MessageHeader.LinkMsgType)
	}
}

func procGatewayMsg(ctx context.Context, jsonInfo packets.JsonUdpInfo, devEui string) {
	switch jsonInfo.MessageHeader.LinkMsgType {
	case packets.GatewayDevInfo:
		procGatewayDevInfoResponse(ctx, jsonInfo, devEui)
	case packets.IotModuleRset:
		procIotModuleResponse(ctx, jsonInfo, devEui)
	case packets.IotModuleStatusChange:
		procIotModuleStatus(ctx, jsonInfo, devEui)
	default:
		globallogger.Log.Errorf("<procGatewayMsg> [DevEui:%s] received unrecognized message type:%s", devEui, jsonInfo.MessageHeader.LinkMsgType)
	}
}

func procTerminalMsg(ctx context.Context, jsonInfo packets.JsonUdpInfo, devEui string) {
	switch jsonInfo.MessageAppHeader.Type {
	case packets.BleConfirm:
		procBleConfirm(ctx, jsonInfo, devEui)
	case packets.BleResponse:
		procBleResponse(ctx, jsonInfo, devEui)
	case packets.BleBoardcast:
		procBleBoardCast(ctx, jsonInfo, devEui)
	case packets.BleCharacteristicNotice:
		procBleCharacteristicNotice(ctx, jsonInfo, devEui)
	case packets.BleTerminalEvent:
		procBleTerminalDisConnect(ctx, jsonInfo, devEui)
	default:
		globallogger.Log.Errorf("<procTerminalMsg> [DevEui:%s] received unrecognized  message type %s", devEui, jsonInfo.MessageHeader.LinkMsgType)
	}
}
